package com.yxinsur.imc.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxinsur.imc.business.domain.ImcContractExpense;
import com.yxinsur.imc.business.domain.ImcContractExpenseExpression;
import com.yxinsur.imc.business.domain.ImcContractVariable;
import com.yxinsur.imc.business.domain.ImcContractVariableStrategy;
import com.yxinsur.imc.business.enums.ExpenseExpressionMsgTypeEnum;
import com.yxinsur.imc.business.enums.YesOrNoEnum;
import com.yxinsur.imc.business.form.ContractExpenseExpressionForm;
import com.yxinsur.imc.business.form.ContractExpenseForm;
import com.yxinsur.imc.business.mapper.ImcContractExpenseExpressionMapper;
import com.yxinsur.imc.business.mapper.ImcContractExpenseMapper;
import com.yxinsur.imc.business.mapper.ImcOrderRiskMapper;
import com.yxinsur.imc.business.service.IImcContractExpenseExpressionService;
import com.yxinsur.imc.business.service.IImcRecnExpenseService;
import com.yxinsur.imc.business.vo.ContractExpenseExpressionMessageVo;
import com.yxinsur.imc.business.vo.ContractExpenseExpressionVo;
import com.yxinsur.imc.business.vo.ContractExpenseVo;
import com.yxinsur.imc.business.vo.ImcContractVariableVo;
import com.yxinsur.imc.common.core.domain.AjaxResult;
import com.yxinsur.imc.common.exception.BusinessException;
import com.yxinsur.imc.common.utils.DateUtils;
import com.yxinsur.imc.common.utils.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 协议-费用科目对应口径（暨口径达式配置）Service业务层处理
 *
 * @author imc
 * @date 2021-07-28
 */
@Service
public class ImcContractExpenseExpressionServiceImpl extends ServiceImpl<ImcContractExpenseExpressionMapper, ImcContractExpenseExpression> implements IImcContractExpenseExpressionService {

    private static final Logger logger = LoggerFactory.getLogger(ImcContractExpenseExpressionServiceImpl.class);

    @Autowired
    private ImcOrderRiskMapper imcOrderRiskMapper;
    @Autowired
    private ImcContractExpenseMapper imcContractExpenseMapper;
    @Autowired
    private ImcContractExpenseExpressionMapper expenseExpressionMapper;
    @Autowired
    private IImcRecnExpenseService recnExpenseService;

    /**
     * 查询协议费用科目口径列表
     *
     * @param id 协议费用科目ID
     * @return 协议费用科目口径列表
     */
    @Override
    public ContractExpenseVo listExpenseExpressionByContractExpenseId(Long id) {
        ContractExpenseVo contractExpenseVo = this.imcContractExpenseMapper.getImcContractExpenseVoById(id);
        List<ContractExpenseExpressionVo> expressionVoList = this.expenseExpressionMapper.listExpenseExpressionVoByContractExpenseId(id, SecurityUtils.getTenantId());
        contractExpenseVo.setContractExpenseId(id);
        contractExpenseVo.setExpressionVoList(expressionVoList);
        return contractExpenseVo;
    }

    /**
     * 协议费用科目-生成&检测口径
     *
     * @param contractExpenseForm ContractExpenseForm
     * @return AjaxResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult checkExpenseExpression(ContractExpenseForm contractExpenseForm) {
        // 返回信息
        ContractExpenseExpressionMessageVo messageVo = new ContractExpenseExpressionMessageVo();
        StringBuilder sqlStr = new StringBuilder();
        StringBuilder tagStr = new StringBuilder();

        // 转换
        for (ContractExpenseExpressionForm item : contractExpenseForm.getContractExpenseExpressionFormList()) {
            // 协议口径变量（如果遇到括弧则直接跳过转换，避免转换成空格）
            ImcContractVariable imcContractVariable = this.expenseExpressionMapper.selectImcContractVariableByName(item.getVariableName());
            String variableName = imcContractVariable.getVariableName();
            String variableLabel = imcContractVariable.getVariableLabel();
            boolean isBracket = "left_bracket".equals(variableName) || "right_bracket".equals(variableName);
            sqlStr.append(isBracket ? variableLabel : variableName);
            tagStr.append(variableLabel);

            // 运算符
            String operator = item.getOperator();
            if (StrUtil.isNotBlank(operator)) {
                sqlStr.append(" ").append(recnExpenseService.transOperator(operator, ExpenseExpressionMsgTypeEnum.SQL.name()));
                tagStr.append(" ").append(recnExpenseService.transOperator(operator, ExpenseExpressionMsgTypeEnum.TAG.name()));
            }

            // 处理策略
            ImcContractVariableStrategy strategy = new ImcContractVariableStrategy();
            if (StrUtil.isNotBlank(item.getStrategyCode())) {
                strategy = this.expenseExpressionMapper.selectImcContractVariableStrategyByCode(item.getStrategyCode());
            }
            String strategyCode = strategy.getStrategyCode();
            String strategyName = strategy.getStrategyName();
            if (StrUtil.isNotBlank(strategyName)) {
                tagStr.append(" ").append(strategyName);
            }

            // 协议口径变量（具体数值）
            String variableValue = item.getVariableValue();
            if (StrUtil.isNotBlank(variableValue)) {
                // 处理策略为“手续费结算当月”或者“手续费结算次月”时，默认数值为“2021-10”+数值
                if ("current_settlement_month".equals(strategyCode) || "next_settlement_month".equals(strategyCode)) {
                    sqlStr.append(" '").append("2021-10-").append(variableValue).append("'");
                    tagStr.append(" '").append("2021-10-").append(variableValue).append("'");
                } else {
                    sqlStr.append(" '").append(variableValue).append("'");
                    tagStr.append(" '").append(variableValue).append("'");
                }
            }

            // 逻辑运算符
            String logicalOperator = item.getLogicalOperator();
            if (StrUtil.isNotBlank(logicalOperator) && !"0".equals(logicalOperator)) {
                sqlStr.append(" ").append(recnExpenseService.transLogicalOperator(logicalOperator, ExpenseExpressionMsgTypeEnum.SQL.name())).append(" ");
                tagStr.append(" ").append(recnExpenseService.transLogicalOperator(logicalOperator, ExpenseExpressionMsgTypeEnum.TAG.name())).append(" ");
            }
        }
        logger.info("协议Id: " + contractExpenseForm.getContractId());
        logger.info("协议费用科目对应口径SQL： " + sqlStr.toString());
        logger.info("协议费用科目对应口径TAG： " + tagStr.toString());
        messageVo.setSqlStr(sqlStr.toString());
        messageVo.setTagStr(tagStr.toString());
        logger.info("messageVo： " + JSONUtil.toJsonStr(messageVo));
        try {
            this.imcOrderRiskMapper.getOrderRiskByCriteria(sqlStr.toString());
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new BusinessException(JSONUtil.toJsonStr(messageVo));
        }
        return AjaxResult.success(messageVo);
    }

    /**
     * 新增协议费用科目
     *
     * @param contractExpenseForm ContractExpenseForm
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult insertImcContractExpenseExpression(ContractExpenseForm contractExpenseForm) {
        // 校验：同一协议不可重复添加同一供应商费用科目与费用科目口径
        ImcContractExpense existImcContractExpense = this.imcContractExpenseMapper.getImcContractExpenseByContractIdAndSupplierExpenseId(contractExpenseForm.getContractId(), contractExpenseForm.getSupplierExpenseId());
        if (ObjectUtil.isNotEmpty(existImcContractExpense)) {
            return AjaxResult.error("相同协议不可重复添加费用科目");
        }

        // 保存：协议费用科目
        ImcContractExpense imcContractExpense = new ImcContractExpense();
        imcContractExpense.setContractId(contractExpenseForm.getContractId());
        imcContractExpense.setSupplierExpenseId(contractExpenseForm.getSupplierExpenseId());
        imcContractExpense.setFeeCalcRule(contractExpenseForm.getFeeCalcRule());
        imcContractExpense.setCreateId(SecurityUtils.getUsername());
        imcContractExpense.setUpdateId(SecurityUtils.getUsername());
        imcContractExpense.setCreateTime(DateUtils.getNowDate());
        imcContractExpense.setUpdateTime(DateUtils.getNowDate());
        imcContractExpense.setIsDeleted(YesOrNoEnum.N.getCode().toString());
        imcContractExpense.setTenantId(SecurityUtils.getTenantId());
        this.imcContractExpenseMapper.insertImcContractExpense(imcContractExpense);

        // 保存：协议费用科目对应口径
        for (ContractExpenseExpressionForm item : contractExpenseForm.getContractExpenseExpressionFormList()) {
            ImcContractExpenseExpression expression = new ImcContractExpenseExpression();
            BeanUtil.copyProperties(item, expression, CopyOptions.create().setIgnoreCase(true));

            ImcContractVariable imcContractVariable = this.expenseExpressionMapper.selectImcContractVariableByName(item.getVariableName());
            expression.setVariableId(imcContractVariable.getId());
            if (StrUtil.isNotBlank(item.getStrategyCode())) {
                ImcContractVariableStrategy imcContractVariableStrategy = this.expenseExpressionMapper.selectImcContractVariableStrategyByCode(item.getStrategyCode());
                expression.setStrategyId(imcContractVariableStrategy.getId());
            }
            expression.setContractExpenseId(imcContractExpense.getId());
            expression.setCreateId(SecurityUtils.getUsername());
            expression.setUpdateId(SecurityUtils.getUsername());
            expression.setCreateTime(DateUtils.getNowDate());
            expression.setUpdateTime(DateUtils.getNowDate());
            expression.setIsDeleted(YesOrNoEnum.N.getCode().toString());
            expression.setTenantId(SecurityUtils.getTenantId());
            expenseExpressionMapper.insertImcContractExpenseExpression(expression);
        }
        return AjaxResult.success();
    }

    /**
     * 修改协议费用科目
     *
     * @param contractExpenseForm ContractExpenseForm
     * @return 结果
     */
    @Override
    public AjaxResult updateImcContractExpenseExpression(ContractExpenseForm contractExpenseForm) {
        // 校验：同一协议不可重复添加同一供应商费用科目与费用科目口径
        ImcContractExpense existImcContractExpense = this.imcContractExpenseMapper.getImcContractExpenseByContractIdAndSupplierExpenseId(contractExpenseForm.getContractId(), contractExpenseForm.getSupplierExpenseId());
        ImcContractExpense imcContractExpense = this.imcContractExpenseMapper.getImcContractExpenseById(contractExpenseForm.getId());
        if (ObjectUtil.isNotEmpty(existImcContractExpense) && !imcContractExpense.getSupplierExpenseId().equals(contractExpenseForm.getSupplierExpenseId())) {
            return AjaxResult.error("相同协议不可重复添加费用科目");
        }

        // 修改：协议费用科目
        imcContractExpense.setSupplierExpenseId(contractExpenseForm.getSupplierExpenseId());
        imcContractExpense.setFeeCalcRule(contractExpenseForm.getFeeCalcRule());
        imcContractExpense.setUpdateId(SecurityUtils.getUsername());
        imcContractExpense.setUpdateTime(DateUtils.getNowDate());
        this.imcContractExpenseMapper.updateImcContractExpense(imcContractExpense);

        // 删除：协议费用科目对应口径
        this.expenseExpressionMapper.deleteExpressionByContractExpenseId(contractExpenseForm.getId());

        // 保存：协议费用科目对应口径
        List<ContractExpenseExpressionForm> expenseExpressionFormList = contractExpenseForm.getContractExpenseExpressionFormList();
        if (CollUtil.isNotEmpty(expenseExpressionFormList)) {
            for (ContractExpenseExpressionForm item : contractExpenseForm.getContractExpenseExpressionFormList()) {
                ImcContractExpenseExpression expression = new ImcContractExpenseExpression();
                BeanUtil.copyProperties(item, expression, CopyOptions.create().setIgnoreCase(true));

                ImcContractVariable imcContractVariable = this.expenseExpressionMapper.selectImcContractVariableByName(item.getVariableName());
                expression.setVariableId(imcContractVariable.getId());
                if (StrUtil.isNotBlank(item.getStrategyCode())) {
                    ImcContractVariableStrategy imcContractVariableStrategy = this.expenseExpressionMapper.selectImcContractVariableStrategyByCode(item.getStrategyCode());
                    expression.setStrategyId(imcContractVariableStrategy.getId());
                }
                expression.setContractExpenseId(imcContractExpense.getId());
                expression.setCreateId(SecurityUtils.getUsername());
                expression.setUpdateId(SecurityUtils.getUsername());
                expression.setCreateTime(DateUtils.getNowDate());
                expression.setUpdateTime(DateUtils.getNowDate());
                expression.setIsDeleted(YesOrNoEnum.N.getCode().toString());
                expression.setTenantId(SecurityUtils.getTenantId());
                this.expenseExpressionMapper.insertImcContractExpenseExpression(expression);
            }
        }
        return AjaxResult.success();
    }

    /**
     * 查询口径变量
     *
     * @return List<ImcContractVariable>
     */
    @Override
    public List<ImcContractVariableVo> listVariable() {
        List<ImcContractVariable> variableList = this.expenseExpressionMapper.listVariable();
        List<ImcContractVariableVo> variableVoList = CollUtil.newArrayList();
        variableList.forEach(item -> {
            ImcContractVariableVo variableVo = new ImcContractVariableVo();
            BeanUtil.copyProperties(item, variableVo);
            variableVo.setVariableItem(JSONUtil.parseArray(item.getVariableItem()));
            variableVoList.add(variableVo);
        });
        return variableVoList;
    }

    /**
     * 查询处理策略
     *
     * @return List<ImcContractVariableStrategy>
     */
    @Override
    public List<ImcContractVariableStrategy> listStrategy() {
        return this.expenseExpressionMapper.listStrategy();
    }
}
